#include <math.h>
#include <string>
#include <iostream>

using std::cout;
using std::endl;
using std::string;

//纯虚函数作为接口存在，派生类实现这些纯虚函数即可完成功能的扩展
//
//当需求发生变化时，希望以最小的代价实现功能的扩展
class Figure
{
public:
    virtual string getName() const=0;
    virtual double getArea() const=0;
};


class Circle
: public Figure
{
public:
    Circle(double radius)
    : _radius(radius)
    {   cout << "Circle(double)" << endl;   }

    string getName() const override
    {   return string("circle");    }

    double getArea() const override
    {   return 3.14 * _radius * _radius;    }

private:
    double _radius;
};

class Rectangle
: public Figure
{
public:
    Rectangle(double length, double width)
    : _length(length)
    , _witdth(width)
    {   cout << "Rectangle(double,double)" << endl;}


    string getName() const override
    {   return string("rectangle");    }

    double getArea() const override
    {   return _length * _witdth;    }


private:
    double _length;
    double _witdth;
};

class Triangle
: public Figure
{
public:
    Triangle(double a, double b, double c)
    : _a(a), _b(b), _c(c)
    {   cout << "Triangle(double,double,double)" <<endl;}

    string getName() const override
    {   return string("triangle");    }

    double getArea() const override
    {   
        double p = (_a + _b + _c) / 2;
        return sqrt(p * (p - _a) * (p - _b) * (p - _c));    
    }

private:
    double _a, _b, _c;
};

void display(Figure & fig)
{
    cout << fig.getName();
    cout << "的面积是:" << fig.getArea() << endl;
}


//如果要考虑扩展性，图形的种类会变多
//create函数的管理就不是很方便了
Figure * createCircle()
{
    //创建Circle时，半径的信息需要通过配置文件*.xml来获取
    //...load xml (预处理)
    Figure * fig = new Circle(10);
    return fig;
}

Figure * createRectangle()
{
    //创建Rectangle时，半径的信息需要通过配置文件*.xml来获取
    //...load xml (预处理)
    Figure * fig = new Rectangle(10, 20);
    return fig;
}

Figure * createTriangle()
{
    //创建Tirangle时，半径的信息需要通过配置文件*.xml来获取
    //...load xml (预处理)
    Figure * fig = new Triangle(3, 4, 5);
    return fig;
}


int main()
{
    Figure * pcircle = createCircle();
    Figure * pRectangle = createRectangle();
    Figure * pTriangle = createTriangle();

    display(*pcircle);
    display(*pRectangle);
    display(*pTriangle);

    return 0;
}

